﻿using System;
using System.Threading;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using System.IO;
using System.Collections.Generic;
#pragma warning disable 67

namespace Pavilion.DesignerTool
{
    public class GraphicsDeviceService : IGraphicsDeviceService
    {
        public ServiceContainer Services { get; private set; }
        public static GraphicsDeviceService Instance { get; private set; }

        private GraphicsDevice graphicsDevice;
        private PresentationParameters parameters;

        public event EventHandler<EventArgs> DeviceCreated, DeviceDisposing, DeviceReset, DeviceResetting;

        private GraphicsDeviceService(IntPtr windowHandle)
        {
            parameters = new PresentationParameters();

            parameters.BackBufferWidth = Math.Max(420, 1);
            parameters.BackBufferHeight = Math.Max(380, 1);
            parameters.BackBufferFormat = SurfaceFormat.Color;
            parameters.DepthStencilFormat = DepthFormat.Depth24;
            parameters.DeviceWindowHandle = windowHandle;
            parameters.PresentationInterval = PresentInterval.Immediate;
            parameters.IsFullScreen = false;

            Services = new ServiceContainer();
            Services.AddService<IGraphicsDeviceService>(this);

            graphicsDevice = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, GraphicsProfile.Reach, parameters);
            OnDeviceCreated();
            GameEngine.Initialize(new Game(), Services, GraphicsDevice, LoadResourceDirectory());
        }

        public static void CreateGraphicsDeviceService(IntPtr windowHandle)
        {
            if (Instance == null)
                Instance = new GraphicsDeviceService(windowHandle);
        }

        private string LoadResourceDirectory()
        {
            string mainDirectory = AppDomain.CurrentDomain.BaseDirectory;
            mainDirectory = mainDirectory.Substring(0, mainDirectory.Length - 1);

            while (!Directory.Exists(mainDirectory + @"\GameContent\"))
                mainDirectory = Directory.GetParent(mainDirectory).FullName;

            return mainDirectory + @"\GameContent\";
        }

        public void Release()
        {
            if (Instance == null)
                return;

            OnDeviceDisposing();

            graphicsDevice.Dispose();
            graphicsDevice = null;
            Instance = null;
        }

        public void ResetDevice(int width, int height)
        {
            OnDeviceResetting();

            parameters.BackBufferWidth = Math.Max(parameters.BackBufferWidth, width);
            parameters.BackBufferHeight = Math.Max(parameters.BackBufferHeight, height);

            graphicsDevice.Reset(parameters);

            OnDeviceReset();
        }

        public GraphicsDevice GraphicsDevice
        {
            get { return graphicsDevice; }
        }

        private void OnDeviceCreated()
        {
            if (DeviceCreated != null)
                DeviceCreated(this, EventArgs.Empty);
        }

        private void OnDeviceDisposing()
        {
            if (DeviceDisposing != null)
                DeviceDisposing(this, EventArgs.Empty);
        }

        private void OnDeviceResetting()
        {
            if (DeviceResetting != null)
                DeviceResetting(this, EventArgs.Empty);
        }

        private void OnDeviceReset()
        {
            if (DeviceReset != null)
                DeviceReset(this, EventArgs.Empty);
        }

        public class ServiceContainer : IServiceProvider
        {
            Dictionary<Type, object> services = new Dictionary<Type, object>();

            public void AddService<T>(T service)
            {
                services.Add(typeof(T), service);
            }

            public object GetService(Type serviceType)
            {
                object service;

                services.TryGetValue(serviceType, out service);

                return service;
            }
        }
    }
}
